package com.j1ay.forum.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.j1ay.forum.dao.mapper.*;
import com.j1ay.forum.model.dto.params.PageParams;
import com.j1ay.forum.model.dto.params.RegisterParams;
import com.j1ay.forum.model.dto.params.UpdateUserParams;
import com.j1ay.forum.model.pojo.JwtUser;
import com.j1ay.forum.model.pojo.po.*;
import com.j1ay.forum.model.pojo.vo.*;
import com.j1ay.forum.service.LoginService;
import com.j1ay.forum.service.UserService;
import com.j1ay.forum.utils.ToolUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.List;
import java.util.concurrent.TimeUnit;


/**
 * @Author J1ay
 * @Date 2021/12/15 14:48
 * @Description
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Autowired(required = false)
    private UserMapper userMapper;

    @Autowired(required = false)
    private RoleMapper roleMapper;

    @Autowired
    private LoginService loginService;

    @Autowired(required = false)
    private AnswerMapper answerMapper;

    @Autowired(required = false)
    private QuestionMapper questionMapper;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired(required = false)
    private PermissionMapper permissionMapper;

    private static final int isStatus = 0;
    @Override
    public JwtUser findUserByUseId(Long userId, String authToken) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getId, userId)
                .select(User::getId, User::getPassword, User::getUsername, User::getNickname, User::getEmail, User::getRoleId)
                .last("limit 1");
        User user = userMapper.selectOne(queryWrapper);
        // 更新用户登录时间
        user.setLastLogin(new Date());
        this.lastLogin(user);

        // 查询用户权限
        List<Permission> permissionList = permissionMapper.findPermissionsByRoleId(user.getRoleId());
        List<SimpleGrantedAuthority> simpleGrantedAuthorities = new ArrayList<>();
        for (int i = 0; i < permissionList.size(); ++i) {
            simpleGrantedAuthorities.add(new SimpleGrantedAuthority(permissionList.get(i).getPath()));
        }
        JwtUser jwtUser = new JwtUser(user.getId(), user.getUsername(), user.getPassword(), simpleGrantedAuthorities);
        //redisTemplate.opsForValue().set("TOKEN_" + authToken, JSON.toJSONString(jwtUser), 1, TimeUnit.DAYS);

        return jwtUser;
    }

    /**
     * 根据username查找用户返回昵称
     * @param username
     * @return
     */
    @Override
    public LoginUserVo findUserVoById(String username) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.select().eq("username", username);
        User user = userMapper.selectOne(queryWrapper);
        // 若是空的
        if (null == user) {
            user = new User();
            user.setNickname("匿名用户");
        }
        LoginUserVo loginUserVo = new LoginUserVo();
        BeanUtils.copyProperties(user, loginUserVo);
        return loginUserVo;
    }

    /**
     * 根据账号查找用户信息
     * @param username
     * @return
     */
    @Override
    public User findUserById(String username) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, username)
                .select(User::getId, User::getPassword, User::getUsername, User::getNickname, User::getEmail, User::getRoleId)
                .last("limit 1");
        User user = userMapper.selectOne(queryWrapper);
        if (null == user) {
            LambdaQueryWrapper<User> queryWrapper1 = new LambdaQueryWrapper<>();
            queryWrapper1.eq(User::getNickname, username)
                    .select(User::getId, User::getPassword, User::getUsername, User::getNickname, User::getEmail,User::getRoleId)
                    .last("limit 1");
            user = userMapper.selectOne(queryWrapper1);
            if (null == user) {
                // email
                LambdaQueryWrapper<User> queryWrapper2 = new LambdaQueryWrapper<>();
                queryWrapper2.eq(User::getEmail, username)
                        .select(User::getId, User::getPassword, User::getUsername, User::getNickname, User::getEmail, User::getRoleId)
                        .last("limit 1");
                user = userMapper.selectOne(queryWrapper2);
            }
        }

        return user;
    }

    /**
     * 根据userId查询用户信息
     * @param id
     * @return
     */
    @Override
    public LoginUserVo findUserByUserId(Long id) {
        if (null == id) {
            return null;
        }
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getId, id)
                .select(User::getId, User::getUsername, User::getNickname, User::getAvatar, User::getEmail, User::getRoleId)
                .last("limit 1");
        User user = userMapper.selectOne(queryWrapper);
        LoginUserVo loginUserVo = new LoginUserVo();
        BeanUtils.copyProperties(user, loginUserVo);

        return loginUserVo;
    }

    /**
     * 注册时，查看username和nickname有没有被注册过
     * @param username
     * @param nickname
     * @return
     */
    @Override
    public int findUserByAccount(String username, String nickname) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        LambdaQueryWrapper<User> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, username)
                .select(User::getUsername)
                .last("limit 1");
        queryWrapper1.eq(User::getNickname, nickname)
                .select(User::getNickname)
                .last("limit 1");
        User user = userMapper.selectOne(queryWrapper);
        User user1 = userMapper.selectOne(queryWrapper1);
        if(null == user) {
            if (null == user1) {
                // 昵称和用户名都未被注册
                return 0;
            }
            else {
                // 昵称被注册
                return 2;
            }
        } else {
            if (null == user1) {
                // 用户名被注册
                return 1;
            }
            else {
                // 昵称和用户名被注册
                return 3;
            }
        }
    }

    /**
     * 用户注册
     * @param registerParams
     * @return
     */
    @Override
    public Result register(RegisterParams registerParams) {
        int type = registerParams.getType();
        if (type == 1) {
            // 通过邮箱进行注册
            return null;
        } else {
            String username = registerParams.getUsername();
            String nickname = registerParams.getNickname();
            String password = registerParams.getPassword();
            Long roleId = registerParams.getRoleId();

            if (StringUtils.isBlank(username) || StringUtils.isBlank(nickname) || StringUtils.isBlank(password)) {
                return Result.fail(ErrorCode.PARAMS_BLANK.getCode(), ErrorCode.PARAMS_BLANK.getMsg());
            }
            int cases = this.findUserByAccount(username, nickname);
            switch (cases) {
                case 1:
                    return Result.fail(ErrorCode.ACCOUNT_USER_IS_EXIST.getCode(), ErrorCode.ACCOUNT_USER_IS_EXIST.getMsg());
                case 2:
                    return Result.fail(ErrorCode.ACCOUNT_NICK_IS_EXIST.getCode(), ErrorCode.ACCOUNT_NICK_IS_EXIST.getMsg());
                case 3:
                    return Result.fail(ErrorCode.ACCOUNT_ALL_IS_EXIST.getCode(), ErrorCode.ACCOUNT_ALL_IS_EXIST.getMsg());
                default:
                    break;
            }

            // 进行注册用户：
            User user = new User();
            password = new BCryptPasswordEncoder().encode(password);
            user.setNickname(nickname);
            user.setUsername(username);
            user.setPassword(password);
            user.setCreateTime(new Date());
            if (null != roleId) {
                user.setRoleId(roleId);
            }
            boolean res = this.saveUser(user);
            if (res) {
                return Result.success(null);
            } else {
                return Result.fail(410, "注册失败，请稍后尝试~");
            }

        }
    }

    @Override
    public boolean saveUser(User user) {
        int res = userMapper.insert(user);;
        return res == 1;
    }

    /**
     * 类型转换 UpdateUserParams - User
     */

    private User toUser(UpdateUserParams updateUserParams) {
        User user = new User();
        BeanUtils.copyProperties(updateUserParams, user);
        return user;
    }

    /**
     * 修改用户个人信息
     * @param updateUserParams
     * @return
     */
    @Override
    public Result updateSelf(UpdateUserParams updateUserParams) {
        Long id = updateUserParams.getId();
        if (null == id) {
            return Result.fail(ErrorCode.PARAMS_BLANK.getCode(), ErrorCode.PARAMS_BLANK.getMsg());
        }
        int res = this.userMapper.updateById(toUser(updateUserParams));
        System.out.println("=========>" + toUser(updateUserParams));
        if (0 == res) {
            return Result.fail(ErrorCode.SESSION_FAILED.getCode(), ErrorCode.SESSION_FAILED.getMsg());
        }
        LoginUserVo loginUserVo = new LoginUserVo();
        BeanUtils.copyProperties(updateUserParams, loginUserVo);

        return Result.success(loginUserVo);
    }

    /**
     * 获取用个人信息（修改前
     * @param id
     * @return
     */
    @Override
    public Result getSelf(Long id) {
        if (null == id) {
            return Result.fail(ErrorCode.PARAMS_BLANK.getCode(), ErrorCode.PARAMS_BLANK.getMsg());
        }
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getId, id)
                .select(User::getUsername,User::getId, User::getNickname, User::getAvatar, User::getEmail, User::getPassword)
                .last("limit 1");

        User user = userMapper.selectOne(queryWrapper);

        UpdateUserParams userParams = new UpdateUserParams();
        BeanUtils.copyProperties(user, userParams);

        return Result.success(userParams);
    }

    /**
     * 更新用户登录时间
     * @param user
     */
    @Override
    public void lastLogin(User user) {
        this.userMapper.updateById(user);
    }

    /**
     * 有权先修改用户信息
     * @param user
     * @return
     */
    @Override
    public Result updateUser(User user) {
        Long id = user.getId();
        if (null == id) {
            return Result.fail(ErrorCode.PARAMS_BLANK.getCode(), ErrorCode.PARAMS_BLANK.getMsg());
        }
        int res = this.userMapper.updateById(user);
        if (0 == res) {
            return Result.fail(ErrorCode.SESSION_FAILED.getCode(), ErrorCode.SESSION_FAILED.getMsg());
        }
        return Result.success(null);
    }


    /**
     * 删除用户
     * @param id
     * @return
     */
    @Override
    public Result delete(Long id) {
        if (null == id) {
            return Result.fail(ErrorCode.PARAMS_BLANK.getCode(), ErrorCode.PARAMS_BLANK.getMsg());
        }
        int res = this.userMapper.deleteById(id);
        if (0 == res) {
            return Result.fail(ErrorCode.SESSION_FAILED.getCode(), ErrorCode.SESSION_FAILED.getMsg());
        }
        return Result.success(null);
    }

    /**
     * 更新用户头像
     * @param fileName
     * @param userId
     * @return
     */
    @Override
    public int uploadTx(String fileName, Long userId) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getId, userId)
                .select(User::getUsername,User::getId, User::getNickname, User::getAvatar, User::getEmail, User::getPassword)
                .last("limit 1");
        User user = userMapper.selectOne(queryWrapper);
        user.setAvatar(fileName);

        return userMapper.updateById(user);
    }

    /**
     * 获取用户个人浏览量点赞数等数据
     * @param username
     * @return
     */
    @Override
    public Result getData(String username) {
        LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Question::getUsername, username)
                .select(Question::getPraise, Question::getViewCount);
        LambdaQueryWrapper<Answer> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(Answer::getUsername, username)
                .select(Answer::getPraise);
        List<Question> questionList = questionMapper.selectList(queryWrapper);
        List<Answer> answers = answerMapper.selectList(queryWrapper1);
        int askNum, answerNum, askPraise = 0, viewCount = 0, answerPraise = 0;
        askNum = questionList.size();
        answerNum = answers.size();
        for (Question question : questionList) {
            askPraise += question.getPraise();
            viewCount += question.getViewCount();
        }

        for (Answer answer : answers) {
            answerPraise += answer.getPraise();
        }

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("askNum",askNum);
        jsonObject.put("answerNum",answerNum);
        jsonObject.put("askPraise",askPraise);
        jsonObject.put("viewCount",viewCount);
        jsonObject.put("answerPraise",answerPraise);

        return Result.success(jsonObject);
    }


    /**
     * 分页获取用户数据
     * @param pageParams
     * @return
     */
    @Override
    public Result getUserList(PageParams pageParams, Long RoleId) {
        if (Objects.isNull(RoleId)) {
            return Result.fail(ErrorCode.PARAMS_BLANK.getCode(), ErrorCode.PARAMS_BLANK.getMsg());
        }
        Page<User> page = new Page<>(pageParams.getPage(), pageParams.getPageSize());
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        System.out.println("==================>" + pageParams.getQueryString());
        if (-1 != RoleId) {
            queryWrapper.eq(User::getRoleId, RoleId);
        }
        if (StringUtils.isNotBlank(pageParams.getQueryString())) {
            queryWrapper.and(c -> c.like(User::getUsername, pageParams.getQueryString())
                    .or().like(User::getEmail, pageParams.getQueryString())
                    .or().like(User::getNickname, pageParams.getQueryString()));
        }
        queryWrapper.orderByDesc(User::getCreateTime, User::getLastLogin);

        Page<User> userPage = userMapper.selectPage(page, queryWrapper);
        List<User> userList = userPage.getRecords();
        List<UserListVo> userListVos = toLoginUserVo(userList);

        PageResult<UserListVo> result = new PageResult();
        result.setCurrentPage(userPage.getCurrent());
        result.setPageSize(userPage.getSize());
        result.setList(userListVos);
        result.setTotals(userPage.getTotal());

        return Result.success(result);
    }

    private List<UserListVo> toLoginUserVo(List<User> userList) {
        List<UserListVo> userListVos = new ArrayList<>();
        for (User user : userList) {
            userListVos.add(userToVo(user));
        }
        return userListVos;
    }

    private UserListVo userToVo(User user) {
        UserListVo userListVo = new UserListVo();
        BeanUtils.copyProperties(user, userListVo);
        Role role = roleMapper.selectById(user.getRoleId());
        userListVo.setRole(role);
        userListVo.setCreateTime(new DateTime(user.getCreateTime()).toString("yyyy-MM-dd HH:mm"));
        userListVo.setLastLogin(new DateTime(user.getLastLogin()).toString("yyyy-MM-dd HH:mm"));
        return userListVo;
    }

    /**
     * 禁用或解禁账号
     * @param userId
     * @return
     */
    @Override
    public Result lockUser(Long userId) {
        User user = userMapper.selectById(userId);
        int status = user.getStatus();
        if (status == 0) {
            user.setStatus(1);
        }
        else {
            user.setStatus(0);
        }
        int res = userMapper.updateById(user);
        if (0 == res) {
            return Result.fail(ErrorCode.SESSION_FAILED.getCode(), ErrorCode.SESSION_FAILED.getMsg());
        }

        return Result.success(null);
    }

    /**
     * 获取验证码
     * @return
     */
    @Override
    public CodeVo getCode() {
        int width = 120;
        int height = 40;
        StringBuffer sb = new StringBuffer();
        Random random = new Random();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics graphic = image.getGraphics();
        graphic.setColor(Color.getColor("F8F8F8"));
        graphic.fillRect(0, 0, width, height);
        Color[] colors = new Color[] { Color.BLUE, Color.GRAY, Color.GREEN, Color.DARK_GRAY,
                Color.BLACK, Color.ORANGE, Color.PINK };
        // 在 "画板"上生成干扰线条
        for (int i = 0; i < 50; i++) {
            graphic.setColor(colors[random.nextInt(colors.length)]);
            final int x = random.nextInt(width);
            final int y = random.nextInt(height);
            final int w = random.nextInt(20);
            final int h = random.nextInt(20);
            final int signA = random.nextBoolean() ? 1 : -1;
            final int signB = random.nextBoolean() ? 1 : -1;
            graphic.drawLine(x, y, x + w * signA, y + h * signB);
        }
        // 绘制字母
        graphic.setFont(new Font("Comic Sans MS", Font.BOLD, 30));
        for (int i = 0; i < 4; i++) {
            final int temp = random.nextInt(26) + 97;
            String s = String.valueOf((char) temp);
            sb.append(s);
            graphic.setColor(colors[random.nextInt(colors.length)]);
            graphic.drawString(s, i * (width / 4), height - (height / 2));
        }
        graphic.dispose();

        ByteArrayOutputStream bs;
        try {
            // 转换成base64
            bs = new ByteArrayOutputStream();
            ImageIO.write(image, "jpg", bs);
            Base64.Encoder encoder = Base64.getEncoder();
            String uuid = ToolUtils.createUUId();
            CodeVo codeVo = new CodeVo();
            codeVo.setBase64("data:image/png;base64," + encoder.encodeToString(bs.toByteArray()));
            codeVo.setUuid(uuid);
            System.out.print(sb.toString());   //TimeUnit.MINUTES.toSeconds(1)
            redisTemplate.opsForValue().set(uuid, sb.toString(), 60, TimeUnit.SECONDS);
            return codeVo;
        } catch (IOException e) {
            log.error(e.getMessage());
            throw new RuntimeException(ErrorCode.SESSION_FAILED.getMsg());
        }
    }
}
